#include "PrimeCore.h"
#include <cmath>
#include <vector>
#include <algorithm>
#include <numeric>
#include <omp.h>

static int threadCount = 1;

// Basic prime operations (existing)
bool isPrime(int number) {
    if (number <= 1) return false;
    if (number == 2) return true;
    if (number % 2 == 0) return false;

    int boundary = static_cast<int>(std::sqrt(number));
    for (int i = 3; i <= boundary; i += 2) {
        if (number % i == 0)
            return false;
    }
    return true;
}

// Prime distribution analysis
int* getPrimesInRange(int start, int end, size_t* count) {
    std::vector<int> primes;
    primes.reserve((end - start) / 2); // Pre-allocate memory

    #pragma omp parallel for num_threads(threadCount)
    for (int n = start; n <= end; ++n) {
        if (isPrime(n)) {
            #pragma omp critical
            primes.push_back(n);
        }
    }

    *count = primes.size();
    int* result = new int[primes.size()];
    std::copy(primes.begin(), primes.end(), result);
    return result;
}

double calculatePrimeDensity(int start, int end) {
    size_t count;
    int* primes = getPrimesInRange(start, end, &count);
    double density = static_cast<double>(count) / (end - start + 1);
    delete[] primes;
    return density;
}

// Large number support
bool isPrimeLL(long long number) {
    if (number <= 1) return false;
    if (number == 2) return true;
    if (number % 2 == 0) return false;

    long long boundary = static_cast<long long>(std::sqrt(number));
    for (long long i = 3; i <= boundary; i += 2) {
        if (number % i == 0)
            return false;
    }
    return true;
}

// Parallel computation control
void setThreadCount(int count) {
    threadCount = count > 0 ? count : 1;
}

// Memory release function (to be called from C#)
extern "C" void freeIntArray(int* array) {
    delete[] array;
}